import myStack.EmptyException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: lishuo
 * Date: 2023-07-23
 * Time: 9:43
 */

// 规定有效元素为：[head,tail)
// 判空判满使用：usedSize
// 下标循环使用：head / tail 与 nums.length 判断
public class CircularQueue {
    // 数组
    private int[] elem;
    // 队头
    private int head;
    // 队尾的下一个
    private int tail;
    // 有效元素个数
    private int usedSize;

    // 使用构造方法，初始化循环队列
    public CircularQueue(int k) {
        this.elem = new int[k];
        this.head = 0;
        this.tail = 0;
        this.usedSize = 0;
    }


    // 1.入队列：put()
    public boolean put(int val) {
        // 判满
        if (isFull()) {
            return false;
        }
        // 正常入队情况
        elem[tail ++] = val;
        // 增加有效元素个数
        usedSize ++;
        // 判断下标
        if (tail == elem.length) {
            tail = 0;
        }
        return true;
    }
    // 2.出队列：take()
    public int take() {
        // 判空
        if (isEmpty()) {
            throw new EmptyException("队列为空!");
        }
        // 正常出队情况
        int val = elem[head ++];
        // 减少有效元素个数
        usedSize --;
        // 判断下标
        if (head == elem.length) {
            head = 0;
        }
        return val;
    }
    // 3.获取队头元素：peekHead()
    public int peekHead() {
        // 判空
        if (isEmpty()) {
            throw new EmptyException("队列为空!");
        }
        int val = elem[head --];
        return val;
    }
    // 4.获取队尾元素：peekTail()
    public int peekTail() {
        // 判空
        if (isEmpty()) {
            throw new EmptyException("队列为空!");
        }
        // 由于 tail 指向最后一个有效元素的下一个，所以需要考虑下标边界情况
        int index = tail == 0? elem.length -1:tail -1;
        int val = elem[index];
        return val;
    }
    // 5.判空：isEmpty()
    public boolean isEmpty() {
        return usedSize == 0;
    }
    // 6.判满：isFull()
    public boolean isFull() {
        return usedSize == elem.length;
    }
    // 7.获取队列有效元素个数：getSize()
    public int getSize() {
        return usedSize;
    }
}
